package com.example.service.impl;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.query_dsl.*;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.json.JsonData;
import com.example.dto.RiskIndicatorDTO;
import com.example.dto.RiskIndicatorQuery;
import com.example.model.RiskIndicator;
import com.example.service.RiskIndicatorService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 风控指标服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class RiskIndicatorServiceImpl implements RiskIndicatorService {

    private static final String INDEX_NAME = "risk_indicators";
    
    private final ElasticsearchClient esClient;
    private RangeQuery.Builder r;

    @Override
    public RiskIndicatorDTO saveIndicator(RiskIndicatorDTO indicatorDTO) {
        try {
            // 如果没有ID，生成一个新的UUID
            if (indicatorDTO.getId() == null || indicatorDTO.getId().isEmpty()) {
                indicatorDTO.setId(UUID.randomUUID().toString());
            }

            // 如果没有计算时间，设置为当前时间
            if (indicatorDTO.getCalculatedAt() == null) {
                indicatorDTO.setCalculatedAt(LocalDateTime.now());
            }

            // 转换为实体对象
            RiskIndicator indicator = indicatorDTO.toEntity();

            // 保存到Elasticsearch
            IndexResponse response = esClient.index(i -> i
                    .index(INDEX_NAME)
                    .id(indicator.getId())
                    .document(indicator)
            );

            log.debug("Saved risk indicator with ID: {}, result: {}", indicator.getId(), response.result());
            return indicatorDTO;
        } catch (IOException e) {
            log.error("Error saving risk indicator: {}", e.getMessage(), e);
            throw new RuntimeException("Failed to save risk indicator", e);
        }
    }

    @Override
    public List<RiskIndicatorDTO> saveIndicators(List<RiskIndicatorDTO> indicatorDTOs) {
        try {
            BulkRequest.Builder bulkRequestBuilder = new BulkRequest.Builder();

            // 准备批量请求
            for (RiskIndicatorDTO dto : indicatorDTOs) {
                // 如果没有ID，生成一个新的UUID
                if (dto.getId() == null || dto.getId().isEmpty()) {
                    dto.setId(UUID.randomUUID().toString());
                }

                // 如果没有计算时间，设置为当前时间
                if (dto.getCalculatedAt() == null) {
                    dto.setCalculatedAt(LocalDateTime.now());
                }

                // 转换为实体对象
                RiskIndicator indicator = dto.toEntity();

                // 添加到批量请求
                bulkRequestBuilder.operations(op -> op
                        .index(idx -> idx
                                .index(INDEX_NAME)
                                .id(indicator.getId())
                                .document(indicator)
                        )
                );
            }

            // 执行批量请求
            BulkResponse response = esClient.bulk(bulkRequestBuilder.build());

            if (response.errors()) {
                log.error("Bulk save had errors: {}", response.items().stream()
                        .filter(item -> item.error() != null)
                        .map(item -> item.error().reason())
                        .collect(Collectors.joining(", ")));
            }

            log.debug("Saved {} risk indicators in bulk", indicatorDTOs.size());
            return indicatorDTOs;
        } catch (IOException e) {
            log.error("Error saving risk indicators in bulk: {}", e.getMessage(), e);
            throw new RuntimeException("Failed to save risk indicators in bulk", e);
        }
    }

    @Override
    public Optional<RiskIndicatorDTO> findById(String id) {
        try {
            GetResponse<RiskIndicator> response = esClient.get(g -> g
                    .index(INDEX_NAME)
                    .id(id),
                    RiskIndicator.class
            );

            if (response.found()) {
                return Optional.of(RiskIndicatorDTO.fromEntity(response.source()));
            } else {
                return Optional.empty();
            }
        } catch (IOException e) {
            log.error("Error finding risk indicator by ID {}: {}", id, e.getMessage(), e);
            throw new RuntimeException("Failed to find risk indicator by ID", e);
        }
    }

    @Override
    public List<RiskIndicatorDTO> findByUserId(String userId) {
        RiskIndicatorQuery query = RiskIndicatorQuery.builder()
                .userIds(Collections.singletonList(userId))
                .build();
        return findByQuery(query);
    }

    @Override
    public List<RiskIndicatorDTO> findByQuery(RiskIndicatorQuery query) {
        try {
            // 构建查询条件
            BoolQuery.Builder boolQueryBuilder = new BoolQuery.Builder();

            // 用户ID条件
            if (query.getUserIds() != null && !query.getUserIds().isEmpty()) {
                boolQueryBuilder.filter(f -> f
                        .terms(t -> t
                                .field("userId")
                                .terms(terms -> terms
                                        .value(query.getUserIds().stream()
                                                .map(FieldValue::of)
                                                .collect(Collectors.toList()))
                                )
                        )
                );
            }

            // 指标类型条件
            if (query.getTypes() != null && !query.getTypes().isEmpty()) {
                boolQueryBuilder.filter(f -> f
                        .terms(t -> t
                                .field("type")
                                .terms(terms -> terms
                                        .value(query.getTypes().stream()
                                                .map(FieldValue::of)
                                                .collect(Collectors.toList()))
                                )
                        )
                );
            }

            // 指标名称条件
            if (query.getNames() != null && !query.getNames().isEmpty()) {
                boolQueryBuilder.filter(f -> f
                        .terms(t -> t
                                .field("name")
                                .terms(terms -> terms
                                        .value(query.getNames().stream()
                                                .map(FieldValue::of)
                                                .collect(Collectors.toList()))
                                )
                        )
                );
            }

            // 风险等级条件
            if (query.getRiskLevels() != null && !query.getRiskLevels().isEmpty()) {
                boolQueryBuilder.filter(f -> f
                        .terms(t -> t
                                .field("riskLevel")
                                .terms(terms -> terms
                                        .value(query.getRiskLevels().stream()
                                                .map(level -> FieldValue.of(level.name()))
                                                .collect(Collectors.toList()))
                                )
                        )
                );
            }

            // 数值范围条件
            if (query.getValueMin() != null || query.getValueMax() != null) {
                RangeQuery rangeQuery = RangeQuery.of(r -> r
                    .number(n -> {
                        NumberRangeQuery.Builder builder = n.field("value");
                        if (query.getValueMin() != null) {
                            builder.gte(query.getValueMin());
                        }
                        if (query.getValueMax() != null) {
                            builder.lte(query.getValueMax());
                        }
                        return builder;
                    })
                );
                boolQueryBuilder.filter(f -> f.range(rangeQuery));
            }

            // 计算时间范围条件
            if (query.getCalculatedAtStart() != null || query.getCalculatedAtEnd() != null) {
                RangeQuery rangeQuery = RangeQuery.of(r -> r
                    .date(d -> {
                        DateRangeQuery.Builder builder = d.field("calculatedAt");
                        if (query.getCalculatedAtStart() != null) {
                            builder.gte(query.getCalculatedAtStart().toString());
                        }
                        if (query.getCalculatedAtEnd() != null) {
                            builder.lte(query.getCalculatedAtEnd().toString());
                        }
                        return builder;
                    })
                );
                boolQueryBuilder.filter(f -> f.range(rangeQuery));
            }

            // 指标来源条件
            if (query.getSources() != null && !query.getSources().isEmpty()) {
                boolQueryBuilder.filter(f -> f
                        .terms(t -> t
                                .field("source")
                                .terms(terms -> terms
                                        .value(query.getSources().stream()
                                                .map(FieldValue::of)
                                                .collect(Collectors.toList()))
                                )
                        )
                );
            }

            // 构建搜索请求
            SearchRequest.Builder searchRequestBuilder = new SearchRequest.Builder()
                    .index(INDEX_NAME)
                    .query(q -> q.bool(boolQueryBuilder.build()));

            // 分页
            if (query.getPage() != null && query.getSize() != null) {
                searchRequestBuilder.from(query.getPage() * query.getSize());
                searchRequestBuilder.size(query.getSize());
            }

            // 排序
            if (query.getSortField() != null && !query.getSortField().isEmpty()) {
                final String sortField = query.getSortField();
                final SortOrder sortOrder = query.getSortDirection() != null &&
                    query.getSortDirection().equalsIgnoreCase("desc") ?
                    SortOrder.Desc : SortOrder.Asc;

                searchRequestBuilder.sort(s -> s
                        .field(f -> f
                                .field(sortField)
                                .order(sortOrder)
                        )
                );
            }
            
            // 执行搜索
            SearchResponse<RiskIndicator> response = esClient.search(
                    searchRequestBuilder.build(),
                    RiskIndicator.class
            );
            
            // 处理结果
            return response.hits().hits().stream()
                    .map(Hit::source)
                    .filter(Objects::nonNull)
                    .map(RiskIndicatorDTO::fromEntity)
                    .collect(Collectors.toList());
        } catch (IOException e) {
            log.error("Error searching risk indicators: {}", e.getMessage(), e);
            throw new RuntimeException("Failed to search risk indicators", e);
        }
    }

    @Override
    public RiskIndicatorDTO calculateIndicator(String userId, String indicatorType) {
        // 这里是示例实现，实际应用中需要根据不同的指标类型实现不同的计算逻辑
        log.info("Calculating risk indicator for user {} of type {}", userId, indicatorType);
        
        // 模拟计算过程
        RiskIndicator.RiskLevel riskLevel;
        double value = Math.random() * 100; // 模拟计算出的指标值
        
        // 根据指标值确定风险等级
        if (value < 25) {
            riskLevel = RiskIndicator.RiskLevel.LOW;
        } else if (value < 50) {
            riskLevel = RiskIndicator.RiskLevel.MEDIUM;
        } else if (value < 75) {
            riskLevel = RiskIndicator.RiskLevel.HIGH;
        } else {
            riskLevel = RiskIndicator.RiskLevel.CRITICAL;
        }
        
        // 创建指标对象
        RiskIndicatorDTO indicatorDTO = RiskIndicatorDTO.builder()
                .id(UUID.randomUUID().toString())
                .userId(userId)
                .type(indicatorType)
                .name("风控指标-" + indicatorType)
                .value(value)
                .riskLevel(riskLevel.name())
                .calculatedAt(LocalDateTime.now())
                .validUntil(LocalDateTime.now().plusDays(7)) // 假设指标有效期为7天
                .source("SYSTEM_CALCULATION")
                .description("系统自动计算的风控指标")
                .attributes(Map.of(
                        "algorithm", "default",
                        "version", "1.0"
                ))
                .build();
        
        // 保存计算结果
        return saveIndicator(indicatorDTO);
    }

    @Override
    public List<RiskIndicatorDTO> calculateIndicators(List<String> userIds, String indicatorType) {
        return userIds.stream()
                .map(userId -> calculateIndicator(userId, indicatorType))
                .collect(Collectors.toList());
    }

    @Override
    public void deleteIndicator(String id) {
        try {
            DeleteResponse response = esClient.delete(d -> d
                    .index(INDEX_NAME)
                    .id(id)
            );
            
            log.debug("Deleted risk indicator with ID: {}, result: {}", id, response.result());
        } catch (IOException e) {
            log.error("Error deleting risk indicator with ID {}: {}", id, e.getMessage(), e);
            throw new RuntimeException("Failed to delete risk indicator", e);
        }
    }

    @Override
    public void deleteUserIndicators(String userId) {
        try {
            DeleteByQueryRequest request = DeleteByQueryRequest.of(d -> d
                    .index(INDEX_NAME)
                    .query(q -> q
                            .term(t -> t
                                    .field("userId")
                                    .value(userId)
                            )
                    )
            );
            
            DeleteByQueryResponse response = esClient.deleteByQuery(request);
            log.debug("Deleted {} risk indicators for user {}", response.deleted(), userId);
        } catch (IOException e) {
            log.error("Error deleting risk indicators for user {}: {}", userId, e.getMessage(), e);
            throw new RuntimeException("Failed to delete user risk indicators", e);
        }
    }

    @Override
    public long deleteByQuery(RiskIndicatorQuery query) {
        try {
            // 构建查询条件，与findByQuery方法类似
            BoolQuery.Builder boolQueryBuilder = new BoolQuery.Builder();
            
            // 用户ID条件
            if (query.getUserIds() != null && !query.getUserIds().isEmpty()) {
                boolQueryBuilder.filter(f -> f
                        .terms(t -> t
                                .field("userId")
                                .terms(terms -> terms
                                        .value(query.getUserIds().stream()
                                                .map(FieldValue::of)
                                                .collect(Collectors.toList()))
                                )
                        )
                );
            }
            
            // 指标类型条件
            if (query.getTypes() != null && !query.getTypes().isEmpty()) {
                boolQueryBuilder.filter(f -> f
                        .terms(t -> t
                                .field("type")
                                .terms(terms -> terms
                                        .value(query.getTypes().stream()
                                                .map(FieldValue::of)
                                                .collect(Collectors.toList()))
                                )
                        )
                );
            }
            
            // 其他条件...
            
            // 执行删除
            DeleteByQueryRequest request = DeleteByQueryRequest.of(d -> d
                    .index(INDEX_NAME)
                    .query(q -> q.bool(boolQueryBuilder.build()))
            );
            
            DeleteByQueryResponse response = esClient.deleteByQuery(request);
            log.debug("Deleted {} risk indicators by query", response.deleted());
            
            return response.deleted();
        } catch (IOException e) {
            log.error("Error deleting risk indicators by query: {}", e.getMessage(), e);
            throw new RuntimeException("Failed to delete risk indicators by query", e);
        }
    }
}